package com.hex.ds.hdtp.core.app.data.configuration.service.Impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.common.util.ExcelDownUtil;
import com.hex.ds.hdtp.core.app.common.util.ExcelExtendUtil;
import com.hex.ds.hdtp.core.app.data.configuration.converter.ITableConvertConverter;
import com.hex.ds.hdtp.core.app.data.configuration.dto.requestDto.TableConvertRequestDto;
import com.hex.ds.hdtp.core.app.data.configuration.dto.response.TableConvertResponseDto;
import com.hex.ds.hdtp.core.app.data.configuration.service.ITableConvertService;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.data.configuration.po.TableConvertPo;
import com.hex.ds.hdtp.core.inf.data.configuration.repository.ITableConvertRepository;
import liquibase.util.file.FilenameUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;

import static com.hex.bigdata.hbda.utils.FileUtil.upload;

/**
 * @Package com.hex.ds.hdtp.core.app.preparation.service.Impl
 * @ClassName ConvertService
 * @Description 装换配置
 * @Author yh.wan
 * @Date 2023/8/7 17:09
 * @Version v1.0
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TableConvertService implements ITableConvertService {

    private final ITableConvertRepository tableConvertRepository;

    private final ITableConvertConverter converter;

    private final IPageAndPageDtoConverter pageAndPageDtoConverter;
    @Value("${file.path}")
    private String filePath;

    /**
     * @Method: toPo <br>
     * @Param: [requestDto] <br>
     * @Return: com.hex.ds.hdtp.core.inf.preparation.po.ConvertPo <br>
     * @Description：REQUEST DTO对象转PO对象<br>
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    private TableConvertPo toPo(TableConvertRequestDto requestDto) {
        return converter.toPo(requestDto);
    }

    /**
     * @Method: queryListByPage
     * @Param: [convertRequestDto, pageDto]
     * @Return: com.hex.ds.hdtp.core.app.common.page.PageData
     * @Description: 分页查询
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    public PageData queryListByPage(TableConvertRequestDto convertRequestDto, PageDto pageDto) {
        final Page<TableConvertPo> pageResult = tableConvertRepository.queryListByPage(
                toPo(convertRequestDto), pageAndPageDtoConverter.toPage(pageDto));
        List<TableConvertResponseDto> responseDtos = converter.toList(pageResult.getData());
        return new PageData(responseDtos, pageResult.getTotal());
    }

    /**
     * @Method: add
     * @Param: [convertRequestDto]
     * @Return: void
     * @Description: 新增
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void add(TableConvertRequestDto convertRequestDto) {
        tableConvertRepository.add(toPo(convertRequestDto));
    }

    /**
     * @Method: modifyById
     * @Param: [convertRequestDto]
     * @Return: void
     * @Description: 修改
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    public void modifyById(TableConvertRequestDto convertRequestDto) {
        tableConvertRepository.modifyById(toPo(convertRequestDto));
    }

    /**
     * @Method: removeById
     * @Param: [pkId]
     * @Return: void
     * @Description: 单个删除
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void removeById(String pkId) {
        tableConvertRepository.removeById(pkId);
    }

    /**
     * @Method: delete
     * @Param: [pkIds]
     * @Return: void
     * @Description: 批量删除
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRemoveById(List<String> pkIds) {
        for (String pkId : pkIds) {
            removeById(pkId);
        }
    }

    /**
     * @Method: download
     * @Param: [request, response, pkIds, toDto]
     * @Return: void
     * @Description: 导出服务器清单
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    @Override
    public void download(HttpServletRequest request, HttpServletResponse response, TableConvertRequestDto convertRequestDto) {
        try {
            String downloadFileName = "转换配置清单-" + DateUtil.format(new DateTime(), "yyyyMMddHHmmss") + ".xlsx";
            Workbook workbook = getWorkbook(convertRequestDto);
            ExcelExtendUtil.datatoResponse(request, response, workbook, downloadFileName);
        } catch (Exception e) {
            log.error("导出失败", e.getStackTrace());
            throw new RuntimeException("导出失败" + e.getMessage());
        }
    }

    /**
     * @param tableConvertRequestDto
     * @Method queryList
     * @Param
     * @Return java.util.List<com.hex.ds.hdtp.core.app.data.configuration.dto.response.TableConvertResponseDto>
     * @Description 不分页查询
     * @Author Wang zhihao
     * @Date 2023/8/14 20:13
     * @Version V1.0
     */
    @Override
    public List<TableConvertResponseDto> queryList(TableConvertRequestDto tableConvertRequestDto) {
        List<TableConvertPo> tableConvertPoList =
                tableConvertRepository.queryList(converter.toPo(tableConvertRequestDto));
        return converter.toList(tableConvertPoList);
    }

    @Override
    public ByteArrayResource exportConvertConfig(List<String> pkIds) {
        String backUpPath = createSavePath();
        String templateFilePath = "static/TableConvertTemplate.xlsx";
        List<TableConvertPo> tableConvertPos = pkIds.stream()
                .map(tableConvertRepository::queryById)
                .collect(Collectors.toList());
        String saveFilePath = backUpPath + File.separator + "转换配置模板.xlsx";
        ExcelDownUtil.generatedExcel(tableConvertPos, templateFilePath, saveFilePath);
        byte[] bytes;
        try {
            bytes = Files.readAllBytes(new File(saveFilePath).toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return new ByteArrayResource(bytes);
    }

    @Override
    public Map<String, Object> importConvertConfig(MultipartFile file) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String backUpFilePath = backupUploadFile(file);
            List<TableConvertPo> TableConvertPos = getExcelData(backUpFilePath);
            saveForExcel(TableConvertPos);
            resultMap.put("status", true);
        } catch (Exception e) {
            resultMap.put("status", false);
            resultMap.put("message", e.getMessage());
        }
        return resultMap;
    }


    /**
     * @Method: downloadOfflineDb
     * @Param: [downloadFileName, pkIds, requestDto]
     * @Return: java.io.File
     * @Description: 下载文件
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    private Workbook getWorkbook(TableConvertRequestDto convertRequestDto) {
        // 模板位置
        String templateFilePath = "static/convert_config.xlsx";
        // 读取模板
        final TemplateExportParams templateExportParams = new TemplateExportParams(templateFilePath);
        // 获取导出数据
        Map<Integer, List<Map<String, Object>>> sheetMap = getDownloadData(convertRequestDto);
        // 生成数据
        return ExcelExportUtil.exportExcelClone(sheetMap, templateExportParams);
    }

    /**
     * @Method: getDownloadData <br>
     * @Param: [convertRequestDto] <br>
     * @Return: java.util.Map<java.lang.Integer, java.util.List < java.util.Map < java.lang.String, java.lang.Object>>> <br>
     * @Description：获取导出数据<br>
     * @Author： yh.wan<br>
     * @Date： 2023/8/7 17:11 <br>
     * @Version： V1.0<br>
     */
    private Map<Integer, List<Map<String, Object>>> getDownloadData(TableConvertRequestDto convertRequestDto) {
        final Map<Integer, List<Map<String, Object>>> sheetMap = new HashMap<>();
        List<TableConvertPo> dataList = tableConvertRepository.queryList(toPo(convertRequestDto));
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("list", dataList.stream().map(t -> JSON.parseObject(JSON.toJSONString(t), Map.class)).collect(Collectors.toList()));
        dataMap.put("sheetName", "转换配置清单");
        sheetMap.put(0, Arrays.asList(dataMap));
        return sheetMap;
    }

    private String createSavePath() {
        String savePath = filePath + File.separator + "static/downExcel/TableConvertTemplate" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false);
        FileUtil.mkdir(savePath);
        return FilenameUtils.separatorsToSystem(savePath);
    }

    private String backupUploadFile(MultipartFile multipartFile) {
        String backUpPath = FilenameUtils.separatorsToSystem(filePath + File.separator + "static/uploadFile/TableConvertTemplate" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false));
        FileUtil.mkdir(backUpPath);
        String updateFilePath = FilenameUtils.separatorsToSystem(backUpPath + File.separator);
        File file = upload(multipartFile, updateFilePath);
        log.debug("上传到服务器的EXCEL文件路径: {}", file.getPath());
        return file.getPath();
    }

    private List<TableConvertPo> getExcelData(String backUpFilePath) {
        ExcelImportResult<TableConvertPo> convertAfterList = readExcel(backUpFilePath);
        return convertAfterList.getList();
    }

    private ExcelImportResult<TableConvertPo> readExcel(String backUpFilePath) {
        ImportParams importParams = new ImportParams();
        importParams.setStartRows(1);
        return ExcelImportUtil.importExcelMore(new File(backUpFilePath), TableConvertPo.class, importParams);
    }

    private void saveForExcel(List<TableConvertPo> tableConvertPos) {
        tableConvertPos.stream()
                .filter(this::isLegitimate)
                .map(tableConvertPo -> {
                    TableConvertRequestDto tableConvertRequestDto = new TableConvertRequestDto();
                    BeanUtils.copyProperties(tableConvertPo, tableConvertRequestDto);
                    return tableConvertRequestDto;
                })
                .forEach(this::add);
    }

    private boolean isLegitimate(TableConvertPo tableConvertPo){
        return !tableConvertPo.getOriginalServer().isEmpty()
                && !tableConvertPo.getTargetServer().isEmpty()
                && !tableConvertPo.getConvertType().isEmpty()
                && !tableConvertPo.getReplaceType().isEmpty()
                && !tableConvertPo.getOriginalValue().isEmpty()
                && !tableConvertPo.getTargetValue().isEmpty()
                && tableConvertPo.getCoefficient() != null;
    }
}
